﻿
// DBBrowserDoc.cpp: CDBBrowserDoc 类的实现
//

#include "pch.h"
#include "framework.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义，并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "DBBrowser.h"
#endif

#include "MainFrm.h"
#include "DBBrowserDoc.h"
#include "DBBrowserView.h"

#include <propkey.h>
#include <fstream>
#include "dbother.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CDBBrowserDoc

IMPLEMENT_DYNCREATE(CDBBrowserDoc, CDocument)

BEGIN_MESSAGE_MAP(CDBBrowserDoc, CDocument)
END_MESSAGE_MAP()


// CDBBrowserDoc 构造/析构

CDBBrowserDoc::CDBBrowserDoc() noexcept
{
	// TODO: 在此添加一次性构造代码
}

CDBBrowserDoc::~CDBBrowserDoc()
{
	if (m_jieba) { delete m_jieba; }
	if (m_codegen) { delete m_codegen; }
}


// CDBBrowserDoc 序列化

void CDBBrowserDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: 在此添加存储代码
	}
	else
	{
		// TODO: 在此添加加载代码
	}
}

#ifdef SHARED_HANDLERS

// 缩略图的支持
void CDBBrowserDoc::OnDrawThumbnail(CDC& dc, LPRECT lprcBounds)
{
	// 修改此代码以绘制文档数据
	dc.FillSolidRect(lprcBounds, RGB(255, 255, 255));

	CString strText = _T("TODO: implement thumbnail drawing here");
	LOGFONT lf;

	CFont* pDefaultGUIFont = CFont::FromHandle((HFONT) GetStockObject(DEFAULT_GUI_FONT));
	pDefaultGUIFont->GetLogFont(&lf);
	lf.lfHeight = 36;

	CFont fontDraw;
	fontDraw.CreateFontIndirect(&lf);

	CFont* pOldFont = dc.SelectObject(&fontDraw);
	dc.DrawText(strText, lprcBounds, DT_CENTER | DT_WORDBREAK);
	dc.SelectObject(pOldFont);
}

// 搜索处理程序的支持
void CDBBrowserDoc::InitializeSearchContent()
{
	CString strSearchContent;
	// 从文档数据设置搜索内容。
	// 内容部分应由“;”分隔

	// 例如:     strSearchContent = _T("point;rectangle;circle;ole object;")；
	SetSearchContent(strSearchContent);
}

void CDBBrowserDoc::SetSearchContent(const CString& value)
{
	if (value.IsEmpty())
	{
		RemoveChunk(PKEY_Search_Contents.fmtid, PKEY_Search_Contents.pid);
	}
	else
	{
		CMFCFilterChunkValueImpl *pChunk = nullptr;
		ATLTRY(pChunk = new CMFCFilterChunkValueImpl);
		if (pChunk != nullptr)
		{
			pChunk->SetTextValue(PKEY_Search_Contents, value, CHUNK_TEXT);
			SetChunkValue(pChunk);
		}
	}
}

#endif // SHARED_HANDLERS

// CDBBrowserDoc 诊断

#ifdef _DEBUG
void CDBBrowserDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CDBBrowserDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG


// CDBBrowserDoc 命令
void CDBBrowserDoc::databaseadapter(std::u16string usql, bool colinfo)
{
	databaseadapter(sqlite::utility::utf16_to_utf8(usql), colinfo);
}

void CDBBrowserDoc::databaseadapter(std::wstring wsql, bool colinfo)
{
	databaseadapter(sqlite::utility::utf16_to_utf8(wsql), colinfo);
}

void CDBBrowserDoc::databaseadapter(std::string sql, bool colinfo)
{
	CDBBrowserView *pView = (CDBBrowserView*)((CFrameWndEx*)AfxGetApp()->m_pMainWnd)->GetActiveView();
	pView->m_List.SetFocus();
	for (size_t i = sql.size() - 1; i > 0; i--) {
		if (sql[i] != ' ' && sql[i] != ';') { sql.erase(i + 1); break; }
	}
	if (lastsql == sql && colinfo || sql.size() == 0) { return; }
	m_sql = sql; m_time = m_itemcount = 0;
	std::string sql_noorder = std::regex_replace(m_sql, 
		std::regex("(\\s+order\\s+by.+?)(\\s+limit\\s+.+)?$", std::regex::icase), "$2");
	try {
		if (colinfo) {
			CMFCRibbonBar *pRibbon = ((CMainFrame*)AfxGetMainWnd())->GetRibbonBar();
			CMFCRibbonComboBox *pColcombo = DYNAMIC_DOWNCAST(CMFCRibbonComboBox, pRibbon->FindByID(ID_COLCOMBO));
			auto ps = m_db << m_sql;
			m_rowid = m_pyjp = -1;
			for (int i = pColcombo->GetCount(); i > 0; i--) { pColcombo->DeleteItem(0); };
			pView->m_List.SetItemCount(0);
			pView->ReFresh();
			for (int i = 0; i < m_columncount; i++) { pView->m_List.DeleteColumn(0); }
			m_columncount = ps.get_column_count();

			for (int i = 0; i < m_columncount; i++) {
				CString colname = ps.get_name16(i);
				if (i == 0 && std::regex_search(sql, std::regex("^\\s*select\\s+(rowid|_rowid_)", std::regex::icase))) {
					m_rowid = 0; pView->m_List.InsertColumn(0, L"rowid", LVCFMT_LEFT, 100, -1); pColcombo->AddItem(L"rowid");
				}
				else {
					pView->m_List.InsertColumn(i, colname, LVCFMT_LEFT, 100, -1);
					if (!colname.CompareNoCase(_T("jp"))) {
						m_pyjp = i;
					}
				}
				pColcombo->AddItem(colname);
			}
			if (pColcombo->FindItem(pColcombo->GetEditText()) == -1) {
				if (!pColcombo->SelectItem(L"key")) { pColcombo->SelectItem(0); }
			}
			ps.used(true);
			lastsql = sql;
		}
		//std::map<int, std::vector<std::vector<std::wstring>>>().swap(m_data);
		m_data.clear();
		m_slowmode = ((m_rowid == -1) || std::regex_search(m_sql,
			std::regex("(\\s+where\\s+|\\s+order\\s+by\\s+(?!rowid(?!\\s+desc)))", std::regex::icase)));
		m_db << "select count(*) from (" + sql_noorder + ");" >> m_rowcount;
		if (m_slowmode) {
			m_itemcount = m_rowcount;
		}
		else {
			m_db << "select max(_rowid_) from (" + sql_noorder + ");" >> m_itemcount;
		}
		pView->m_List.SetItemCount(m_itemcount);
		m_datathread = AfxBeginThread(GetPageDataByThread, this);
		auto pStatusBar = (CMFCRibbonStatusBar*)((CFrameWndEx*)AfxGetMainWnd())->GetPane(AFX_IDW_STATUS_BAR);
		auto pStatusBarPane = (CMFCRibbonStatusBarPane*)(pStatusBar->FindElement(ID_STATUSBAR_PANE2));
		CString jls;
		jls.Format(_T("共%d条"), m_rowcount);
		pStatusBarPane->SetText(jls);
		pStatusBarPane->Redraw();
		//AfxMessageBox((std::to_wstring(b1 - b) + L" " + std::to_wstring(b2 - b1) + L" " + std::to_wstring(b3 - b2) + L" ").data());
	}
	catch (sqlite::sqlite_exception& e) {
		pView->m_List.SetItemCount(0);
		auto pStatusBar = (CMFCRibbonStatusBar*)((CFrameWndEx*)AfxGetMainWnd())->GetPane(AFX_IDW_STATUS_BAR);
		auto pStatusBarPane = (CMFCRibbonStatusBarPane*)(pStatusBar->FindElement(ID_STATUSBAR_PANE2));
		pStatusBarPane->SetText(_T("共0条"));
		pStatusBarPane->Redraw();
		if (m_sql_where.empty() && m_sql_order.empty()) {
			for (int i = 0; i < m_columncount; i++) { pView->m_List.DeleteColumn(0); }
			Cleartblinfo();
		}
		pView->m_focus.iItem = -1;
		pView->m_focus.iSubItem = 0;
		SetTitle(L"");
		MessageBoxA(*AfxGetApp()->m_pMainWnd, e.get_msg(), 0, 0);
	}
}

void CDBBrowserDoc::GetPageData()
{
	// TODO: 在此处添加实现代码.

	CDBBrowserView *pView = (CDBBrowserView *)((CFrameWndEx*)AfxGetApp()->m_pMainWnd)->GetActiveView();
	
	time_t begin = clock();
	int top = pView->m_List.GetTopIndex();
	int bottom = top + pView->m_List.GetCountPerPage();
	int toppage = top / m_pagesize;
	int bottompage = (top + pView->m_List.GetCountPerPage()) / m_pagesize;
	wchar_t *nulltext = L"";
	for (int index = toppage; index <= bottompage; index++) {
		if (m_data.find(index) == m_data.end()) {
			std::string sql = "";
			if (m_slowmode) {
				sql = "select * from (" + m_sql + ") limit " + std::to_string(index*m_pagesize) + "," + std::to_string(m_pagesize);
			}
			else {
				sql = "select * from (" + m_sql + ") where _rowid_>" + std::to_string(index*m_pagesize) + " limit " + std::to_string(m_pagesize);
			}
			auto ps = m_db << sql;
			std::vector<std::vector<std::wstring>> m_pagedata;
			while (ps.step() == SQLITE_ROW) {
				std::vector<std::wstring> m_linedata;
				for (int i = 0; i < m_columncount; i++) {
					auto pt = ps.get_text16(i);
					m_linedata.push_back(pt ? pt : nulltext);
				}
				m_pagedata.push_back(m_linedata);
			}
			m_data[index] = m_pagedata;
		}
	}
	m_time = clock() - begin;
}


void CDBBrowserDoc::Cleartblinfo()
{
	// TODO: 在此处添加实现代码.
	lastsql = m_sql = m_sql_order = m_sql_select = m_sql_where = "";
	m_rowid = m_pyjp = -1;
	m_rowcount = m_itemcount = 0;
	m_table = L"";
	m_root = L"";
	m_tbl = L"";
	m_data.clear();
}


void CDBBrowserDoc::LoadDictFromRes(WORD ID) {
	HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(ID), L"dict");
	DWORD dwSize = SizeofResource(NULL, hRsrc);
	HGLOBAL hGlobal = LoadResource(NULL, hRsrc);
	LPVOID pBuffer = LockResource(hGlobal);
	if (m_codegen) { m_codegen->GetDict()->LoadDict((const char*)pBuffer, dwSize); }
	else { m_codegen = new Hanzi::CodeGenerater((const char*)pBuffer, dwSize); }
	GlobalUnlock(hGlobal);
}


UINT GetPageDataByThread(LPVOID lp) {
	if (lp != 0) { 
		CDBBrowserDoc *pDoc = (CDBBrowserDoc*)lp;
		pDoc->GetPageData();
		POSITION pos = pDoc->GetFirstViewPosition();
		CDBBrowserView *pView = (CDBBrowserView*)pDoc->GetNextView(pos);
		pView->ReFresh();
		pDoc->m_datathread = nullptr;
	}
	return 0;
}


UINT ExportTableToFileByThread(LPVOID lp) {
	if (!lp) { return 0; }
	auto pinfo = (_EXPORTDB*)lp;
	CString sql = pinfo->sql;
	auto db = &pinfo->pDoc->m_db;
	bool utf16 = pinfo->utf16;
	char delimiter = pinfo->delimiter;
	auto comp = &pinfo->pDoc->m_task->comp[pinfo->taskid];

	std::ofstream outfile(pinfo->path, std::ios::out | std::ios::trunc | std::ios::binary);
	try {
		auto p = *db << sql;
		int cols = p.get_column_count();
		if (cols == 0) { return 1; }
		size_t rows = 0, cur = 0, len = 0;
		if (utf16) {
			outfile.write("\xFF\xFE", 2);
			std::wstring buf = L"", buff = L"", line = L"";
			std::wstring ss = L"\n\r\"";
			ss += delimiter;
			while (p.step() == SQLITE_ROW) {
				line.clear();
				for (int i = 0; i < cols; i++) {
					auto t = p.get_text16(i);
					line += delimiter;
					if (t) {
						buf = t;
						if (buf.find_first_of(ss) == std::wstring::npos) { line += buf; }
						else {
							cur = buf.find(L"\""), len = buf.size();
							while (cur != std::wstring::npos && cur <= len) {
								buf.replace(cur, 1, L"\"\"");
								cur += 2, len++;
								cur = buf.find(L"\"", cur);
							}
							line += L'\"'; line += buf; line += L'\"';
						}
					}
				}
				buff += line.data() + 1;
				buff += L'\n'; rows++;
				if (rows % 10000 == 0) {
					outfile.write((char*)buff.data(), buff.length() * 2);
					buff.clear();
				}
				*comp = rows;
			}
			if (buff.length()) {
				outfile.write((char*)buff.data(), buff.length() * 2);
				buff.clear();
			}
		}
		else {
			outfile.write("\xEF\xBB\xBF", 3);
			std::string buf = "", buff = "", line = "";
			std::string ss = "\n\r\"" + delimiter;
			while (p.step() == SQLITE_ROW) {
				line.clear();
				for (int i = 0; i < cols; i++) {
					auto t = p.get_text(i);
					line += delimiter;
					if (t) {
						buf = t;
						if (buf.find_first_of(ss) == std::string::npos) { line += buf; }
						else {
							cur = buf.find("\""), len = buf.size();
							while (cur != std::string::npos && cur <= len) {
								buf.replace(cur, 1, "\"\"");
								cur += 2, len++;
								cur = buf.find("\"", cur);
							}
							line += '\"'; line += buf; line += '\"';
						}
					}
				}
				buff += line.data() + 1;
				buff += '\n'; rows++;
				if (rows % 10000 == 0) {
					outfile.write(buff.data(), buff.length());
					buff.clear();
				}
				*comp = rows;
			}
			if (buff.length()) {
				outfile.write(buff.data(), buff.length());
				buff.clear();
			}
		}
	}
	catch (sqlite::sqlite_exception& e) {
		MessageBoxA(*AfxGetApp()->m_pMainWnd, e.get_msg(), 0, 0);
	}
	outfile.close();
	pinfo->pDoc->m_task->tasks--;
	if (!pinfo->pDoc->m_task->tasks) { pinfo->pDoc->m_task->end = clock(); }
	delete pinfo;
	return 0;
}


UINT ImportTableByThread(LPVOID lp) {
	if (!lp) { return 1; }
	auto pinfo = (_IMPORTDB*)lp;
	auto mmap = mio::mmap_source(pinfo->path.GetString());
	if (!mmap.is_open() || !mmap.is_mapped() || !mmap.length()) { delete lp; return 1; }
	std::string encoding = Hanzi::Dict::GuessEncoding(mmap.data(), min(512, mmap.length()));
	time_t b = clock();
	if (!pinfo->pDoc->m_transaction) {
		pinfo->pDoc->m_db << "begin;";
		pinfo->pDoc->m_transaction = true;
	}
	if (encoding == "ansi") {
		_import_template<char, std::wstring>(pinfo, mmap.data(), mmap.size());
	}
	else if (encoding == "utf16le") {
		_import_template<wchar_t, std::wstring>(pinfo, mmap.data(), mmap.size());
	}
	else if (encoding == "utf8") {
		_import_template<char, std::string>(pinfo, mmap.data(), mmap.size());
	}
	else {}
	pinfo->pDoc->m_task->tasks--; pinfo->pDoc->m_task->fresh = true;
	if (!pinfo->pDoc->m_task->tasks) { pinfo->pDoc->m_task->end = clock(); }
	if (pinfo->pGen) { delete pinfo->pGen; }
	delete pinfo;
	//AfxMessageBox((L"导入完成，用时" + std::to_wstring(clock() - b) + L"ms").data());
	return 0;
}

template<typename T, typename TS>
void _import_template(_IMPORTDB *pinfo, const char *data, size_t size) {
	csv::Reader<T> csv;
	csv.parse(data, size);
	csv.infos.delimiter = pinfo->delimiter;
	csv.infos.quote_character = pinfo->quote_character;
	csv.infos.first_row_is_header = pinfo->first_row_is_header;
	auto db = pinfo->pDoc->m_db;
	auto p = db << sqlite::utility::utf16_to_utf8(pinfo->sql.GetString());
	int paras = p.get_bind_para_count();
	int CRLF = pinfo->CRLF;
	pinfo->pDoc->m_task->total += size / sizeof(T);
	auto pcomp = &pinfo->pDoc->m_task->comp[pinfo->taskid];
	bool duoyi = pinfo->duoyi;

	TS value; size_t len = 0, n = 0;
	std::vector<TS> rowdata;
	TS def;
	if (sizeof(T) == 1) {
		def = (T*)pinfo->default.data();
	}
	else {
		int u16len = MultiByteToWideChar(CP_UTF8, NULL, pinfo->default.data(), pinfo->default.size(), NULL, NULL);
		wchar_t *Buffer = new wchar_t[u16len + 1];
		MultiByteToWideChar(CP_UTF8, NULL, pinfo->default.data(), pinfo->default.size(), Buffer, u16len);
		Buffer[u16len] = '\0';
		def = (T*)Buffer;
	}
	void(*importline)(sqlite::database_binder&, std::vector<TS>&, int&, _IMPORTDB*);
	importline = (pinfo->duoyi ? (pinfo->pinyin ? &_ImportLine_duoyi_py<TS> : &_ImportLine_duoyi<TS>)
		: pinfo->pGen ? (pinfo->pinyin ? &_ImportLine_py_gen<TS> : &_ImportLine_gen<TS>)
		: (pinfo->pinyin ? &_ImportLine_py<TS> : &_ImportLine<TS>));
	for (auto row : csv) {
		*pcomp += row.size() + CRLF;
		if (row.size() <= 0) { continue; }
		rowdata.clear(); n = 0;
		for (auto cell : row) {
			cell.read_value(value); n++;
			rowdata.push_back(std::move(value));
		}
		if (!duoyi) { for (; n < paras; n++) { rowdata.push_back(def); } }
		(*importline)(p, rowdata, paras, pinfo);
	}
}
template<> void _import_template<char, std::wstring>(_IMPORTDB *pinfo, const char *data, size_t size) {
	csv::Reader<char> csv;
	csv.parse(data, size);
	csv.infos.delimiter = pinfo->delimiter;
	csv.infos.quote_character = pinfo->quote_character;
	csv.infos.first_row_is_header = pinfo->first_row_is_header;
	auto db = pinfo->pDoc->m_db;
	auto p = db << sqlite::utility::utf16_to_utf8(pinfo->sql.GetString());
	int paras = p.get_bind_para_count();
	int CRLF = pinfo->CRLF;
	pinfo->pDoc->m_task->total += size;
	auto pcomp = &pinfo->pDoc->m_task->comp[pinfo->taskid];
	bool duoyi = pinfo->duoyi;

	std::string value; size_t u16len = 0, BufferSize = 1024, n = 0;
	wchar_t *Buffer = new wchar_t[BufferSize];
	std::vector<std::wstring> rowdata;
	u16len = MultiByteToWideChar(CP_UTF8, NULL, pinfo->default.data(), pinfo->default.size(), NULL, NULL);
	if (u16len + 1 > BufferSize) {
		delete[] Buffer;
		BufferSize = 2 * (u16len + 1);
		Buffer = new wchar_t[BufferSize];
	}
	MultiByteToWideChar(CP_UTF8, NULL, pinfo->default.data(), pinfo->default.size(), Buffer, u16len);
	Buffer[u16len] = '\0';
	std::wstring def = Buffer;
	void(*importline)(sqlite::database_binder&, std::vector<std::wstring>&, int&, _IMPORTDB*);
	importline = (pinfo->duoyi ? (pinfo->pinyin ? &_ImportLine_duoyi_py<std::wstring> : &_ImportLine_duoyi<std::wstring>)
		: pinfo->pGen ? (pinfo->pinyin ? &_ImportLine_py_gen<std::wstring> : &_ImportLine_gen<std::wstring>)
		: (pinfo->pinyin ? &_ImportLine_py<std::wstring> : &_ImportLine<std::wstring>));
	for (auto row : csv) {
		*pcomp += row.size() + CRLF;
		if (row.size() <= 0) { continue; }
		rowdata.clear(); n = 0;
		for (auto cell : row) {
			value.clear();
			cell.read_value(value);
			u16len = MultiByteToWideChar(936, NULL, value.data(), value.size(), NULL, NULL);
			if (u16len + 1 > BufferSize) {
				delete[] Buffer;
				BufferSize = 2 * (u16len + 1);
				Buffer = new wchar_t[BufferSize];
			}
			MultiByteToWideChar(936, NULL, value.data(), value.size(), Buffer, u16len);
			Buffer[u16len] = '\0'; n++;
			rowdata.push_back(std::move(std::wstring(Buffer, u16len)));
		}
		if (!duoyi) { for (; n < paras; n++) { rowdata.push_back(def); } }
		(*importline)(p, rowdata, paras, pinfo);
	}
	delete[] Buffer;
}


cppjieba::MixSegment * CDBBrowserDoc::GetJieba()
{
	// TODO: 在此处添加实现代码.
	if (m_jieba == nullptr) {
		HRSRC hRsrc1 = FindResource(NULL, MAKEINTRESOURCE(IDR_DICT_HMM), L"dict");
		DWORD dwSize1 = SizeofResource(NULL, hRsrc1);
		HGLOBAL hGlobal1 = LoadResource(NULL, hRsrc1);
		LPVOID pBuffer1 = LockResource(hGlobal1);
		HRSRC hRsrc2 = FindResource(NULL, MAKEINTRESOURCE(IDR_DICT_JIEBA), L"dict");
		DWORD dwSize2 = SizeofResource(NULL, hRsrc2);
		HGLOBAL hGlobal2 = LoadResource(NULL, hRsrc2);
		LPVOID pBuffer2 = LockResource(hGlobal2);
		m_jieba = new cppjieba::MixSegment((const char*)pBuffer2, dwSize2, (const char*)pBuffer1, dwSize1);
		GlobalUnlock(hGlobal1); GlobalUnlock(hGlobal2);
	}
	return m_jieba;
}


std::string CDBBrowserDoc::trad2simp(std::string str)
{
	static std::unordered_map<std::string, std::string> t2sdict;
	if (t2sdict.size() == 0) {
		HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDR_DICT_S2T), L"dict");
		DWORD dwSize = SizeofResource(NULL, hRsrc);
		HGLOBAL hGlobal = LoadResource(NULL, hRsrc);
		LPVOID pBuffer = LockResource(hGlobal);
		csv::Reader<char> csv;
		csv.parse((char*)pBuffer, dwSize);
		csv.infos.delimiter = '\t';
		std::vector<std::string> r; std::string t;
		for (auto row : csv) {
			if (row.size() == 0) { continue; }
			r.clear();
			for (auto cell : row) {
				cell.read_value(t);
				r.push_back(std::move(t));
			}
			for (size_t i = 1; i < r.size(); i++) { t2sdict[r[i]] = r[0]; }
		}
		GlobalUnlock(hGlobal);
	}
	auto beg = str.data();
	auto cur = beg;
	auto end = beg + str.size();
	int len = 0;
	std::vector<std::string> chars;
	while (cur <= end) {
		if (!(cur[0] & 0x80)) {
			cur++; continue;
		}
		else if ((uint8_t)cur[0] <= 0xdf) { len = 2; }
		else if ((uint8_t)cur[0] <= 0xef) { len = 3; }
		else if ((uint8_t)cur[0] <= 0xf7) { len = 4; }
		else if ((uint8_t)cur[0] <= 0xfb) { len = 5; }
		else if ((uint8_t)cur[0] <= 0xfd) { len = 6; }
		else { cur += 6; continue; };
		chars.push_back(str.substr(cur - beg, len));
		cur += len;
	}
	std::unordered_map<std::string, std::string>::iterator it;
	std::string res; res.reserve(str.size());
	for (size_t i = 0; i < chars.size(); i++) {
		it = t2sdict.find(chars[i]);
		if (it == t2sdict.end()) { res += chars[i]; }
		else { res += it->second; }
	}
	return std::move(res);
}


bool CDBBrowserDoc::IsGB2312(std::string word)
{
	static std::unordered_map<std::string, bool> GBdict;
	if (GBdict.size() == 0) {
		HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDR_DICT_GB2312), L"dict");
		DWORD dwSize = SizeofResource(NULL, hRsrc);
		HGLOBAL hGlobal = LoadResource(NULL, hRsrc);
		LPVOID pBuffer = LockResource(hGlobal);
		csv::Reader<char> csv;
		csv.parse((char*)pBuffer, dwSize);
		csv.infos.delimiter = '\t';
		std::string t;
		for (auto row : csv) {
			if (row.size() == 0) { continue; }
			GBdict[std::string(row.data(), row.size())] = true;
		}
		GlobalUnlock(hGlobal);
	}
	return GBdict.find(word) != GBdict.end();
}


std::wstring CDBBrowserDoc::GetDefaultCreateSQL(CString &table, bool default)
{
	std::wstring t = table;
	std::wstring sql = L"create table " + table + L" (";
	if (std::regex_search(t, std::wregex(L"pinyin", std::wregex::icase))) {
		for (auto i : { L"\"jp\"",L",\"key\"",L",\"value\"" }) {
			sql += i + std::wstring(L" text not null default ''");
		}
		sql += std::wstring(L",\"weight\" interger not null default 5000");
	}
	else if (std::regex_search(t, std::wregex(L"ebglish", std::wregex::icase))) {
		sql += std::wstring(L"\"key\" text not null default '' collate nocase,\"weight\" interger default 5000");
	}
	else if (std::regex_search(t, std::wregex(L"cliphistory", std::wregex::icase))) {
		sql += std::wstring(L"\"value\" text not null default ''");
	}
	else if (std::regex_search(t, std::wregex(L"customs", std::wregex::icase))) {
		for (auto i : { L"\"key\"",L",\"value\"" }) {
			sql += i + std::wstring(L" text not null default ''");
		}
		sql += std::wstring(L",\"comment\" text not null default '001'");
	}
	else if (std::regex_search(t, std::wregex(L"hotstrings|functions|symbol", std::wregex::icase))) {
		for (auto i : { L"\"key\"",L",\"value\"",L",\"comment\"" }) {
			sql += i + std::wstring(L" text not null default ''");
		}
	}
	else if (default) {
		for (auto i : { L"\"key\"",L",\"value\"" }) {
			sql += i + std::wstring(L" text not null default ''");
		}
		sql += std::wstring(L",\"weight\" interger not null default 1");
	}
	else
		return L"";
	sql += L")";
	return sql;
}
